- Main Page
- Related Pages
- Files

# timers.c

Go to the documentation of this file.

    00001 /*
    00002  * $Id: timers.c,v 1.15 2004/03/13 19:55:34 troth Exp $
    00003  *
    00004  ****************************************************************************
    00005  *
    00006  * simulavr - A simulator for the Atmel AVR family of microcontrollers.
    00007  * Copyright (C) 2001, 2002, 2003, 2004  Theodore A. Roth
    00008  *
    00009  * This program is free software; you can redistribute it and/or modify
    00010  * it under the terms of the GNU General Public License as published by
    00011  * the Free Software Foundation; either version 2 of the License, or
    00012  * (at your option) any later version.
    00013  *
    00014  * This program is distributed in the hope that it will be useful,
    00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00017  * GNU General Public License for more details.
    00018  *
    00019  * You should have received a copy of the GNU General Public License
    00020  * along with this program; if not, write to the Free Software
    00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    00022  *
    00023  ****************************************************************************
    00024  */
    00025
    00026 /**
    00027  * \file timers.c
    00028  * \brief Module to simulate the AVR's on-board timer/counters.
    00029  *
    00030  * This currently only implements the timer/counter 0.
    00031  */
    00032
    00033 #include <config.h>
    00034
    00035 #include <stdio.h>
    00036 #include <stdlib.h>
    00037 #include <string.h>
    00038
    00039 #include "avrerror.h"
    00040 #include "avrmalloc.h"
    00041 #include "avrclass.h"
    00042 #include "utils.h"
    00043 #include "callback.h"
    00044 #include "op_names.h"
    00045
    00046 #include "storage.h"
    00047 #include "flash.h"
    00048
    00049 #include "vdevs.h"
    00050 #include "memory.h"
    00051 #include "stack.h"
    00052 #include "register.h"
    00053 #include "sram.h"
    00054 #include "eeprom.h"
    00055 #include "timers.h"
    00056 #include "ports.h"
    00057
    00058 #include "avrcore.h"
    00059
    00060 #include "intvects.h"
    00061
    00062 #ifndef DOXYGEN
    00063
    00064 /* *INDENT-OFF* */
    00065
    00066 Timer16Def global_timer16_defs[] = {
    00067     {
    00068         .timer_name = "Timer1",
    00069         .tcnth_name = "TCNT1H",
    00070         .tcntl_name = "TCNT1L",
    00071         .tccra_name = "TCCR1A",
    00072         .tccrb_name = "TCCR1B",
    00073         .base = 0x4c,
    00074         .tof = bit_TOV1,
    00075         .ocf_a = bit_OCF1A,
    00076         .ocf_b = bit_OCF1B,
    00077         .ocf_c = 8
    00078     }
    00079 };
    00080
    00081 OCReg16Def global_ocreg16_defs[] = {
    00082     {
    00083         .ocrdev_name = "OCR1A",
    00084         .ocrl_name = "OCR1AL",
    00085         .ocrh_name = "OCR1AH",
    00086         .base = 0x4a
    00087     },
    00088     {
    00089         .ocrdev_name = "OCR1B",
    00090         .ocrl_name = "OCR1BL",
    00091         .ocrh_name = "OCR1BH",
    00092         .base = 0x48
    00093     },
    00094     {
    00095         .ocrdev_name = "OCR1C",
    00096         .ocrl_name = "OCR1CL",
    00097         .ocrh_name = "OCR1CH",
    00098         .base = 0x78},
    00099     {
    00100         .ocrdev_name = "OCR3A",
    00101         .ocrl_name = "OCR3AL",
    00102         .ocrh_name = "OCR3A",
    00103         .base = 0x86
    00104     },
    00105     {
    00106         .ocrdev_name = "OCR3B",
    00107         .ocrl_name = "OCR3BL",
    00108         .ocrh_name = "OCR3BH",
    00109         .base = 0x84
    00110     },
    00111     {
    00112         .ocrdev_name = "OCR3C",
    00113         .ocrl_name = "OCR3CL",
    00114         .ocrh_name = "OCR3CH",
    00115         .base = 0x82
    00116     }
    00117 };
    00118 /* *INDENT-ON* */
    00119
    00120 #endif /* not DOXYGEN */
    00121
    00122 /****************************************************************************\
    00123  *
    00124  * Timer/Counter 0
    00125  *
    00126 \****************************************************************************/
    00127
    00128 static void timer_iadd_addr (VDevice *vdev, int addr, char *name,
    00129                              int rel_addr, void *data);
    00130 static uint8_t timer_intr_read (VDevice *dev, int addr);
    00131 static void timer_intr_write (VDevice *dev, int addr, uint8_t val);
    00132 static void timer_intr_reset (VDevice *dev);
    00133 static int timer_intr_cb (uint64_t time, AvrClass *data);
    00134
    00135 /** \brief Allocate a new timer interrupt */
    00136
    00137 VDevice *
    00138 timer_int_create (int addr, char *name, int rel_addr, void *data)
    00139 {
    00140     uint8_t *func_mask = (uint8_t *) data;
    00141     if (data)
    00142         return (VDevice *)timer_intr_new (addr, name, *func_mask);
    00143     else
    00144         avr_error ("Attempted timer interrupt create with NULL data pointer");
    00145     return 0;
    00146 }
    00147
    00148 TimerIntr_T *
    00149 timer_intr_new (int addr, char *name, uint8_t func_mask)
    00150 {
    00151     TimerIntr_T *ti;
    00152
    00153     ti = avr_new (TimerIntr_T, 1);
    00154     timer_intr_construct (ti, addr, name, func_mask);
    00155     class_overload_destroy ((AvrClass *)ti, timer_intr_destroy);
    00156
    00157     return ti;
    00158 }
    00159
    00160 /** \brief Constructor for timer interrupt object. */
    00161
    00162 void
    00163 timer_intr_construct (TimerIntr_T *ti, int addr, char *name,
    00164                       uint8_t func_mask)
    00165 {
    00166     if (ti == NULL)
    00167         avr_error ("passed null ptr");
    00168
    00169     vdev_construct ((VDevice *)ti, timer_intr_read, timer_intr_write,
    00170                     timer_intr_reset, timer_iadd_addr);
    00171
    00172     ti->func_mask = func_mask;
    00173
    00174     timer_iadd_addr ((VDevice *)ti, addr, name, 0, NULL);
    00175
    00176     timer_intr_reset ((VDevice *)ti);
    00177 }
    00178
    00179 static void
    00180 timer_iadd_addr (VDevice *vdev, int addr, char *name, int rel_addr,
    00181                  void *data)
    00182 {
    00183     TimerIntr_T *ti = (TimerIntr_T *)vdev;
    00184
    00185     if (strncmp ("TIFR", name, 4) == 0)
    00186     {
    00187         ti->tifr_addr = addr;
    00188     }
    00189
    00190     else if (strncmp ("TIMSK", name, 5) == 0)
    00191     {
    00192         ti->timsk_addr = addr;
    00193     }
    00194
    00195     else
    00196     {
    00197         avr_error ("invalid Timer Interrupt register name: '%s' @ 0x%04x",
    00198                    name, addr);
    00199     }
    00200 }
    00201
    00202 /** \brief Destructor for timer interrupt object. */
    00203
    00204 void
    00205 timer_intr_destroy (void *ti)
    00206 {
    00207     if (ti == NULL)
    00208         return;
    00209
    00210     vdev_destroy (ti);
    00211 }
    00212
    00213 static uint8_t
    00214 timer_intr_read (VDevice *dev, int addr)
    00215 {
    00216     TimerIntr_T *ti = (TimerIntr_T *)dev;
    00217
    00218     if (addr == ti->timsk_addr)
    00219     {
    00220         return (ti->timsk & ti->func_mask);
    00221     }
    00222
    00223     else if (addr == ti->tifr_addr)
    00224     {
    00225         return (ti->tifr & ti->func_mask);
    00226     }
    00227
    00228     else
    00229     {
    00230         avr_error ("Bad address: 0x%04x", addr);
    00231     }
    00232
    00233     return 0;                   /* will never get here */
    00234 }
    00235
    00236 static void
    00237 timer_intr_write (VDevice *dev, int addr, uint8_t val)
    00238 {
    00239     TimerIntr_T *ti = (TimerIntr_T *)dev;
    00240     CallBack *cb;
    00241
    00242     if (addr == ti->timsk_addr)
    00243     {
    00244         ti->timsk = (val & ti->func_mask);
    00245         if (ti->timsk == 0)
    00246         {
    00247             ti->intr_cb = NULL; /* no interrupt are enabled, remove the
    00248                                    callback */
    00249         }
    00250         else if (ti->intr_cb == NULL)
    00251         {
    00252             /* we need to install the intr_cb function */
    00253             cb = callback_new (timer_intr_cb, (AvrClass *)ti);
    00254             ti->intr_cb = cb;
    00255             avr_core_async_cb_add ((AvrCore *)vdev_get_core (dev), cb);
    00256         }
    00257     }
    00258
    00259     else if (addr == ti->tifr_addr)
    00260     {
    00261         ti->tifr &= ~(val & ti->func_mask);
    00262     }
    00263
    00264     else
    00265     {
    00266         avr_error ("Bad address: 0x%04x", addr);
    00267     }
    00268 }
    00269
    00270 static void
    00271 timer_intr_reset (VDevice *dev)
    00272 {
    00273     TimerIntr_T *ti = (TimerIntr_T *)dev;
    00274
    00275     ti->intr_cb = NULL;
    00276
    00277     ti->timsk = 0;
    00278     ti->tifr = 0;
    00279 }
    00280
    00281 static int
    00282 timer_intr_cb (uint64_t time, AvrClass *data)
    00283 {
    00284     TimerIntr_T *ti = (TimerIntr_T *)data;
    00285     uint8_t intrs = ti->timsk & ti->tifr & ti->func_mask;
    00286
    00287     if (ti->intr_cb == NULL)
    00288         return CB_RET_REMOVE;
    00289
    00290     if (intrs)
    00291     {
    00292         AvrCore *core = (AvrCore *)vdev_get_core ((VDevice *)ti);
    00293
    00294         /*
    00295          * FIXME: Once an irq has been raised, the flag should be cleared,
    00296          *   _BUT_ should it be done here? Might be a problem if there are
    00297          *   many interrupts pending and then the user wants to clear one.
    00298          */
    00299
    00300         if (intrs & mask_TOV0)
    00301         {
    00302             avr_core_irq_raise (core, irq_vect_table_index (TIMER0_OVF));
    00303             ti->tifr &= ~mask_TOV0;
    00304         }
    00305         else if (intrs & mask_ICF1)
    00306         {
    00307             avr_core_irq_raise (core, irq_vect_table_index (TIMER1_CAPT));
    00308             ti->tifr &= ~mask_ICF1;
    00309         }
    00310         else if (intrs & mask_OCF1B)
    00311         {
    00312             avr_core_irq_raise (core, irq_vect_table_index (TIMER1_COMPB));
    00313             ti->tifr &= ~mask_OCF1B;
    00314         }
    00315         else if (intrs & mask_OCF1A)
    00316         {
    00317             avr_core_irq_raise (core, irq_vect_table_index (TIMER1_COMPA));
    00318             ti->tifr &= ~mask_OCF1A;
    00319         }
    00320         else if (intrs & mask_TOV1)
    00321         {
    00322             avr_core_irq_raise (core, irq_vect_table_index (TIMER1_OVF));
    00323             ti->tifr &= ~mask_TOV1;
    00324         }
    00325         else
    00326         {
    00327             avr_error ("An invalid interrupt was flagged");
    00328         }
    00329     }
    00330
    00331     return CB_RET_RETAIN;
    00332 }
    00333
    00334 /****************************************************************************\
    00335  *
    00336  * Timer/Counter 0
    00337  *
    00338 \****************************************************************************/
    00339
    00340 static void timer0_add_addr (VDevice *vdev, int addr, char *name,
    00341                              int rel_addr, void *data);
    00342 static uint8_t timer0_read (VDevice *dev, int addr);
    00343 static void timer0_write (VDevice *dev, int addr, uint8_t val);
    00344 static void timer0_reset (VDevice *dev);
    00345 static int timer0_clk_incr_cb (uint64_t ck, AvrClass *data);
    00346
    00347 /** \brief Allocate a new timer/counter 0. */
    00348
    00349 VDevice *
    00350 timer0_create (int addr, char *name, int rel_addr, void *data)
    00351 {
    00352     return (VDevice *)timer0_new (addr, name, rel_addr);
    00353 }
    00354
    00355 Timer0_T *
    00356 timer0_new (int addr, char *name, int rel_addr)
    00357 {
    00358     Timer0_T *timer;
    00359
    00360     timer = avr_new (Timer0_T, 1);
    00361     timer0_construct (timer, addr, name, rel_addr);
    00362     class_overload_destroy ((AvrClass *)timer, timer0_destroy);
    00363
    00364     return timer;
    00365 }
    00366
    00367 /** \brief Constructor for timer/counter 0 object. */
    00368
    00369 void
    00370 timer0_construct (Timer0_T *timer, int addr, char *name, int rel_addr)
    00371 {
    00372     if (timer == NULL)
    00373         avr_error ("passed null ptr");
    00374
    00375     vdev_construct ((VDevice *)timer, timer0_read, timer0_write, timer0_reset,
    00376                     timer0_add_addr);
    00377
    00378     timer0_add_addr ((VDevice *)timer, addr, name, 0, NULL);
    00379     if (rel_addr)
    00380         timer->related_addr = rel_addr;
    00381     timer0_reset ((VDevice *)timer);
    00382 }
    00383
    00384 /** \brief Destructor for timer/counter 0 object. */
    00385
    00386 void
    00387 timer0_destroy (void *timer)
    00388 {
    00389     if (timer == NULL)
    00390         return;
    00391
    00392     vdev_destroy (timer);
    00393 }
    00394
    00395 static void
    00396 timer0_add_addr (VDevice *vdev, int addr, char *name, int rel_addr,
    00397                  void *data)
    00398 {
    00399     Timer0_T *ti = (Timer0_T *)vdev;
    00400
    00401     if (strncmp ("TCNT", name, 4) == 0)
    00402     {
    00403         ti->tcnt_addr = addr;
    00404     }
    00405
    00406     else if (strncmp ("TCCR", name, 4) == 0)
    00407     {
    00408         ti->tccr_addr = addr;
    00409     }
    00410
    00411     else
    00412     {
    00413         avr_error ("invalid Timer register name: '%s' @ 0x%04x", name, addr);
    00414     }
    00415 }
    00416
    00417 static uint8_t
    00418 timer0_read (VDevice *dev, int addr)
    00419 {
    00420     Timer0_T *timer = (Timer0_T *)dev;
    00421
    00422     if (addr == timer->tcnt_addr)
    00423         return timer->tcnt;
    00424
    00425     else if (addr == timer->tccr_addr)
    00426         return timer->tccr;
    00427
    00428     else
    00429     {
    00430         avr_error ("Bad address: 0x%04x", addr);
    00431     }
    00432
    00433     return 0;                   /* will never get here */
    00434 }
    00435
    00436 static void
    00437 timer0_write (VDevice *dev, int addr, uint8_t val)
    00438 {
    00439     Timer0_T *timer = (Timer0_T *)dev;
    00440     CallBack *cb;
    00441
    00442     if (addr == timer->tcnt_addr)
    00443     {
    00444         timer->tcnt = val;
    00445     }
    00446
    00447     else if (addr == timer->tccr_addr)
    00448     {
    00449         /*
    00450          * When the user writes toe TCCR, a callback is installed for either
    00451          * clock generated increments or externally generated increments. The
    00452          * two incrememtor callback are mutally exclusive, only one or the
    00453          * other can be installed at any given instant.
    00454          */
    00455
    00456         /* timer 0 only has clock select function. */
    00457         timer->tccr = val & mask_CS;
    00458
    00459         switch (timer->tccr)
    00460         {
    00461             case CS_STOP:
    00462                 /* stop either of the installed callbacks */
    00463                 timer->clk_cb = timer->ext_cb = NULL;
    00464                 timer->divisor = 0;
    00465                 return;
    00466             case CS_EXT_FALL:
    00467             case CS_EXT_RISE:
    00468                 /* FIXME: not implemented yet */
    00469                 avr_error ("external timer/counter sources is not implemented"
    00470                            " yet");
    00471                 return;
    00472             case CS_CK:
    00473                 timer->divisor = 1;
    00474                 break;
    00475             case CS_CK_8:
    00476                 timer->divisor = 8;
    00477                 break;
    00478             case CS_CK_64:
    00479                 timer->divisor = 64;
    00480                 break;
    00481             case CS_CK_256:
    00482                 timer->divisor = 256;
    00483                 break;
    00484             case CS_CK_1024:
    00485                 timer->divisor = 1024;
    00486                 break;
    00487             default:
    00488                 avr_error ("The impossible happened!");
    00489         }
    00490         /* remove external incrementor if installed */
    00491         if (timer->ext_cb)
    00492             timer->ext_cb = NULL;
    00493
    00494         /* install the clock incrementor callback (with flair!) */
    00495         if (timer->clk_cb == NULL)
    00496         {
    00497             cb = callback_new (timer0_clk_incr_cb, (AvrClass *)timer);
    00498             timer->clk_cb = cb;
    00499             avr_core_clk_cb_add ((AvrCore *)vdev_get_core ((VDevice *)timer),
    00500                                  cb);
    00501         }
    00502     }
    00503
    00504     else
    00505     {
    00506         avr_error ("Bad address: 0x%04x", addr);
    00507     }
    00508 }
    00509
    00510 static void
    00511 timer0_reset (VDevice *dev)
    00512 {
    00513     Timer0_T *timer = (Timer0_T *)dev;
    00514
    00515     timer->clk_cb = NULL;
    00516     timer->ext_cb = NULL;
    00517
    00518     timer->tccr = 0;
    00519     timer->tcnt = 0;
    00520
    00521     timer->divisor = 0;
    00522 }
    00523
    00524 static int
    00525 timer0_clk_incr_cb (uint64_t ck, AvrClass *data)
    00526 {
    00527     Timer0_T *timer = (Timer0_T *)data;
    00528     uint8_t last = timer->tcnt;
    00529     TimerIntr_T *ti;
    00530
    00531     ti = (TimerIntr_T *)avr_core_get_vdev_by_addr ((AvrCore *)
    00532                                                    vdev_get_core ((VDevice *)
    00533                                                                   timer),
    00534                                                    timer->related_addr);
    00535
    00536     if (timer->clk_cb == NULL)
    00537         return CB_RET_REMOVE;
    00538
    00539     if (timer->divisor <= 0)
    00540         avr_error ("Bad divisor value: %d", timer->divisor);
    00541
    00542     /* Increment clock if ck is a mutliple of divisor. Since divisor is always
    00543        a power of 2, it's much faster to do the bitwise AND instead of using
    00544        the integer modulus operator (%). */
    00545     timer->tcnt += ((ck & (timer->divisor - 1)) == 0);
    00546
    00547     /* Check if tcnt rolled over and if so, set the overflow flag.  If
    00548        overflow interrupts are set? what if they aren't? This is set
    00549        irregardless of whether SREG-I or TOIE0 are set (overflow interrupt
    00550        enabled) and thus allows the interrupt to be pending until manually
    00551        cleared (writing a one to the TOV0 flag) or interrupts are enabled. My
    00552        interpretation of the datasheets. See datasheet discussion of TIFR.
    00553        TRoth */
    00554     if ((timer->tcnt == 0) && (timer->tcnt != last))
    00555         ti->tifr |= mask_TOV0;
    00556
    00557     return CB_RET_RETAIN;
    00558 }
    00559
    00560 /****************************************************************************\
    00561 *
    00562 * Timer/Counter 1/3 (16 bit)
    00563 *
    00564 \****************************************************************************/
    00565
    00566 /** \name 16 Bit Timer Functions */
    00567
    00568 /*@{*/
    00569
    00570 static void timer16_add_addr (VDevice *vdev, int addr, char *name,
    00571                               int rel_addr, void *data);
    00572 static void timer16_destroy (void *timer);
    00573 static uint8_t timer16_read (VDevice *dev, int addr);
    00574 static void timer16_write (VDevice *dev, int addr, uint8_t val);
    00575 static void timer16_reset (VDevice *dev);
    00576 static int timer16_clk_incr_cb (uint64_t time, AvrClass *data);
    00577 static void timer16_handle_tccr_write (Timer16_T *timer);
    00578
    00579 /** \brief Allocate a new 16 bit timer/counter. */
    00580
    00581 VDevice *
    00582 timer16_create (int addr, char *name, int rel_addr, void *data)
    00583 {
    00584     uint8_t *def_data = (uint8_t *) data;
    00585     if (data)
    00586         return (VDevice *)timer16_new (addr, name, rel_addr,
    00587                                        global_timer16_defs[*def_data]);
    00588     else
    00589         avr_error ("Attempted timer 16 create with NULL data pointer");
    00590     return 0;
    00591 }
    00592
    00593 Timer16_T *
    00594 timer16_new (int addr, char *name, int rel_addr, Timer16Def timerdef)
    00595 {
    00596     Timer16_T *timer;
    00597
    00598     timer = avr_new (Timer16_T, 1);
    00599     timer16_construct (timer, addr, name, rel_addr, timerdef);
    00600     class_overload_destroy ((AvrClass *)timer, timer16_destroy);
    00601
    00602     return timer;
    00603 }
    00604
    00605 /** \brief Constructor for 16 bit timer/counter object. */
    00606
    00607 void
    00608 timer16_construct (Timer16_T *timer, int addr, char *name, int rel_addr,
    00609                    Timer16Def timerdef)
    00610 {
    00611     if (timer == NULL)
    00612         avr_error ("passed null ptr");
    00613
    00614     vdev_construct ((VDevice *)timer, timer16_read, timer16_write,
    00615                     timer16_reset, timer16_add_addr);
    00616
    00617     timer->timerdef = timerdef;
    00618
    00619     timer16_add_addr ((VDevice *)timer, addr, name, 0, NULL);
    00620     if (rel_addr)
    00621         timer->related_addr = rel_addr;
    00622     timer16_reset ((VDevice *)timer);
    00623 }
    00624
    00625 static void
    00626 timer16_add_addr (VDevice *vdev, int addr, char *name, int rel_addr,
    00627                   void *data)
    00628 {
    00629     Timer16_T *ti = (Timer16_T *)vdev;
    00630
    00631     if (strncmp ("TCNTL", name, 5) == 0)
    00632     {
    00633         ti->tcntl_addr = addr;
    00634     }
    00635
    00636     else if (strncmp ("TCNTH", name, 5) == 0)
    00637     {
    00638         ti->tcnth_addr = addr;
    00639     }
    00640
    00641     else if (strncmp ("TCCRA", name, 5) == 0)
    00642     {
    00643         ti->tccra_addr = addr;
    00644     }
    00645
    00646     else if (strncmp ("TCCRB", name, 5) == 0)
    00647     {
    00648         ti->tccrb_addr = addr;
    00649     }
    00650
    00651     else if (strncmp ("TCCRC", name, 5) == 0)
    00652     {
    00653         ti->tccrc_addr = addr;
    00654     }
    00655
    00656     else
    00657     {
    00658         avr_error ("invalid Timer16 register name: '%s' @ 0x%04x", name,
    00659                    addr);
    00660     }
    00661 }
    00662
    00663 static void
    00664 timer16_destroy (void *timer)
    00665 {
    00666     if (timer == NULL)
    00667         return;
    00668
    00669     vdev_destroy (timer);
    00670 }
    00671
    00672 static uint8_t
    00673 timer16_read (VDevice *dev, int addr)
    00674 {
    00675     Timer16_T *timer = (Timer16_T *)dev;
    00676
    00677     if (addr == timer->tcntl_addr)
    00678     {
    00679         timer->TEMP = (uint8_t) ((timer->tcnt) >> 8);
    00680         return (timer->tcnt) & 0xFF;
    00681     }
    00682
    00683     else if (addr == timer->tcnth_addr)
    00684     {
    00685         return timer->TEMP;
    00686     }
    00687
    00688     else if (addr == timer->tccra_addr)
    00689     {
    00690         return timer->tccra;
    00691     }
    00692
    00693     else if (addr == timer->tccrb_addr)
    00694     {
    00695         return timer->tccrb;
    00696     }
    00697
    00698     else if (addr == timer->tccrc_addr)
    00699     {
    00700         return timer->tccrc;
    00701     }
    00702
    00703     else
    00704     {
    00705         avr_error ("Bad address: 0x%04x", addr);
    00706     }
    00707
    00708     return 0;                   /* will never get here */
    00709 }
    00710
    00711 static void
    00712 timer16_write (VDevice *dev, int addr, uint8_t val)
    00713 {
    00714     Timer16_T *timer = (Timer16_T *)dev;
    00715
    00716     if (addr == timer->tcntl_addr)
    00717     {
    00718         timer->tcnt = (((timer->TEMP) << 8) & 0xFF00) | val;
    00719     }
    00720
    00721     else if (addr == timer->tcnth_addr)
    00722     {
    00723         timer->TEMP = val;
    00724     }
    00725
    00726     else if (addr == timer->tccra_addr)
    00727     {
    00728         timer->tccra = val;
    00729         timer16_handle_tccr_write (timer);
    00730     }
    00731
    00732     else if (addr == timer->tccrb_addr)
    00733     {
    00734         timer->tccrb = val;
    00735         timer16_handle_tccr_write (timer);
    00736     }
    00737
    00738     else if (addr == timer->tccrc_addr)
    00739     {
    00740         timer->tccrc = val;
    00741         timer16_handle_tccr_write (timer);
    00742     }
    00743
    00744     else
    00745     {
    00746         avr_error ("Bad address: 0x%04x", addr);
    00747     }
    00748 }
    00749
    00750 static void
    00751 timer16_reset (VDevice *dev)
    00752 {
    00753     Timer16_T *timer = (Timer16_T *)dev;
    00754
    00755     timer->clk_cb = NULL;
    00756     timer->ext_cb = NULL;
    00757
    00758     timer->tccra = 0;
    00759     timer->tccrb = 0;
    00760     timer->tccrc = 0;
    00761     timer->tcnt = 0;
    00762
    00763     timer->divisor = 0;
    00764 }
    00765
    00766 static void
    00767 timer_intr_set_flag (TimerIntr_T *ti, uint8_t bitnr)
    00768 {
    00769     ti->tifr |= bitnr;
    00770 }
    00771
    00772 static int
    00773 timer16_clk_incr_cb (uint64_t ck, AvrClass *data)
    00774 {
    00775     Timer16_T *timer = (Timer16_T *)data;
    00776     uint16_t last = timer->tcnt;
    00777
    00778     if (!timer->ti)
    00779         timer->ti =
    00780             (TimerIntr_T *)avr_core_get_vdev_by_addr ((AvrCore *)
    00781                                                       vdev_get_core ((VDevice
    00782                                                                       *)
    00783                                                                      timer),
    00784                                                       timer->related_addr);
    00785
    00786     if (timer->clk_cb == NULL)
    00787         return CB_RET_REMOVE;
    00788
    00789     /* Increment clock if ck is a mutliple of divisor. Since divisor is always
    00790        a power of 2, it's much faster to do the bitwise AND instead of using
    00791        the integer modulus operator (%). */
    00792     timer->tcnt += ((ck & (timer->divisor - 1)) == 0);
    00793
    00794     if (timer->divisor <= 0)
    00795         avr_error ("Bad divisor value: %d", timer->divisor);
    00796
    00797     /* The following things only have to be checked if the counter value has
    00798        changed */
    00799     if (timer->tcnt != last)
    00800     {
    00801         /* An overflow occurred */
    00802         if (timer->tcnt == 0)
    00803             timer_intr_set_flag (timer->ti, mask_TOV1);
    00804
    00805         /* The counter value matches one of the ocr values */
    00806         if (timer->ocra && (timer->tcnt == timer->ocra->ocr))
    00807         {
    00808             timer_intr_set_flag (timer->ti, mask_OCF1A);
    00809         }
    00810
    00811         if (timer->ocrb && (timer->tcnt == timer->ocrb->ocr))
    00812         {
    00813             timer_intr_set_flag (timer->ti, mask_OCF1B);
    00814         }
    00815     }
    00816     return CB_RET_RETAIN;
    00817 }
    00818
    00819 #if 0
    00820 static void
    00821 timer_intr_clear_flag (TimerIntr_T *ti, uint8_t bitnr)
    00822 {
    00823     ti->tifr &= ~(bitnr);
    00824 }
    00825 #endif
    00826
    00827 static void
    00828 timer16_handle_tccr_write (Timer16_T *timer)
    00829 {
    00830     int cs;
    00831     CallBack *cb;
    00832     /*
    00833      * When the user writes toe TCCR, a callback is installed for either
    00834      * clock generated increments or externally generated increments. The
    00835      * two incrememtor callback are mutally exclusive, only one or the
    00836      * other can be installed at any given instant.
    00837      */
    00838
    00839     cs = timer->tccrb & 0x07;
    00840
    00841     switch (cs)
    00842     {
    00843         case CS_STOP:
    00844             /* stop either of the installed callbacks */
    00845             timer->clk_cb = timer->ext_cb = NULL;
    00846             timer->divisor = 0;
    00847             return;
    00848         case CS_EXT_FALL:
    00849         case CS_EXT_RISE:
    00850             /* FIXME: not implemented yet */
    00851             avr_error ("external timer/counter sources is not implemented"
    00852                        "yet");
    00853             return;
    00854         case CS_CK:
    00855             timer->divisor = 1;
    00856             break;
    00857         case CS_CK_8:
    00858             timer->divisor = 8;
    00859             break;
    00860         case CS_CK_64:
    00861             timer->divisor = 64;
    00862             break;
    00863         case CS_CK_256:
    00864             timer->divisor = 256;
    00865             break;
    00866         case CS_CK_1024:
    00867             timer->divisor = 1024;
    00868             break;
    00869         default:
    00870             avr_error ("The impossible happened!");
    00871     }
    00872     /* remove external incrementor if installed */
    00873     if (timer->ext_cb)
    00874         timer->ext_cb = NULL;
    00875
    00876     /* install the clock incrementor callback (with flair!) */
    00877     if (timer->clk_cb == NULL)
    00878     {
    00879         cb = callback_new (timer16_clk_incr_cb, (AvrClass *)timer);
    00880         timer->clk_cb = cb;
    00881         avr_core_clk_cb_add ((AvrCore *)vdev_get_core ((VDevice *)timer), cb);
    00882     }
    00883 }
    00884
    00885 /*@}*/
    00886
    00887 /****************************************************************************\
    00888  *
    00889  * Timer16OCR(VDevice) : 16bit - Timer/Counter - Output Compare Register
    00890  *
    00891 \****************************************************************************/
    00892
    00893 /** \name 16 Bit Output Compare Register Functions */
    00894
    00895 /*@{*/
    00896
    00897 static void ocr_add_addr (VDevice *vdev, int addr, char *name, int rel_addr,
    00898                           void *data);
    00899 static void ocreg16_destroy (void *ocr);
    00900 static uint8_t ocreg16_read (VDevice *dev, int addr);
    00901 static void ocreg16_write (VDevice *dev, int addr, uint8_t val);
    00902 static void ocreg16_reset (VDevice *dev);
    00903
    00904 /** \brief Allocate a new 16 bit Output Compare Register
    00905   * \param ocrdef The definition struct for the \a OCR to be created
    00906   */
    00907
    00908 VDevice *
    00909 ocreg16_create (int addr, char *name, int rel_addr, void *data)
    00910 {
    00911     uint8_t *def_data = (uint8_t *) data;
    00912     if (data)
    00913         return (VDevice *)ocreg16_new (addr, name,
    00914                                        global_ocreg16_defs[*def_data]);
    00915     else
    00916         avr_error ("Attempted OCReg create with NULL data pointer");
    00917     return 0;
    00918 }
    00919
    00920 OCReg16_T *
    00921 ocreg16_new (int addr, char *name, OCReg16Def ocrdef)
    00922 {
    00923     OCReg16_T *ocreg;
    00924
    00925     ocreg = avr_new (OCReg16_T, 1);
    00926     ocreg16_construct (ocreg, addr, name, ocrdef);
    00927     class_overload_destroy ((AvrClass *)ocreg, ocreg16_destroy);
    00928
    00929     return ocreg;
    00930 }
    00931
    00932 /** \brief Constructor for 16 bit Output Compare Register object. */
    00933
    00934 void
    00935 ocreg16_construct (OCReg16_T *ocreg, int addr, char *name, OCReg16Def ocrdef)
    00936 {
    00937     if (ocreg == NULL)
    00938         avr_error ("passed null ptr");
    00939
    00940     vdev_construct ((VDevice *)ocreg, ocreg16_read, ocreg16_write,
    00941                     ocreg16_reset, ocr_add_addr);
    00942
    00943     ocreg->ocrdef = ocrdef;
    00944
    00945     ocr_add_addr ((VDevice *)ocreg, addr, name, 0, NULL);
    00946     ocreg16_reset ((VDevice *)ocreg);
    00947 }
    00948
    00949 static void
    00950 ocr_add_addr (VDevice *vdev, int addr, char *name, int rel_addr, void *data)
    00951 {
    00952     OCReg16_T *ocreg = (OCReg16_T *)vdev;
    00953
    00954     if ((strncmp ("OCRAL", name, 5) == 0) || (strncmp ("OCRBL", name, 5) == 0)
    00955         || (strncmp ("OCRCL", name, 5) == 0))
    00956     {
    00957         ocreg->ocrl_addr = addr;
    00958     }
    00959
    00960     else if ((strncmp ("OCRAH", name, 5) == 0)
    00961              || (strncmp ("OCRBH", name, 5) == 0)
    00962              || (strncmp ("OCRCH", name, 5) == 0))
    00963
    00964     {
    00965         ocreg->ocrh_addr = addr;
    00966     }
    00967
    00968     else
    00969     {
    00970         avr_error ("invalid Timer16 register name: '%s' @ 0x%04x", name,
    00971                    addr);
    00972     }
    00973 }
    00974
    00975 static void
    00976 ocreg16_destroy (void *ocreg)
    00977 {
    00978     if (ocreg == NULL)
    00979         return;
    00980
    00981     vdev_destroy (ocreg);
    00982 }
    00983
    00984 static uint8_t
    00985 ocreg16_read (VDevice *dev, int addr)
    00986 {
    00987     OCReg16_T *ocreg = (OCReg16_T *)dev;
    00988
    00989     if (addr == ocreg->ocrl_addr)
    00990     {
    00991         return (ocreg->ocr) & 0xFF;
    00992     }
    00993
    00994     else if (addr == ocreg->ocrh_addr)
    00995     {
    00996         return (ocreg->ocr) >> 8;
    00997     }
    00998
    00999     else
    01000     {
    01001         avr_error ("Bad address: 0x%04x", addr);
    01002     }
    01003
    01004     return 0;
    01005 }
    01006
    01007 static void
    01008 ocreg16_write (VDevice *dev, int addr, uint8_t val)
    01009 {
    01010     OCReg16_T *ocreg = (OCReg16_T *)dev;
    01011
    01012     if (addr == ocreg->ocrl_addr)
    01013     {
    01014         ocreg->ocr = (((ocreg->TEMP) << 8) & 0xFF00) | val;
    01015     }
    01016
    01017     else if (addr == ocreg->ocrh_addr)
    01018     {
    01019         ocreg->TEMP = val;
    01020     }
    01021
    01022     else
    01023     {
    01024         avr_error ("Bad address: 0x%04x", addr);
    01025     }
    01026 }
    01027
    01028 static void
    01029 ocreg16_reset (VDevice *dev)
    01030 {
    01031     OCReg16_T *ocreg = (OCReg16_T *)dev;
    01032
    01033     ocreg->ocr = 0;
    01034 }
    01035
    01036 /*@}*/

Automatically generated by Doxygen 1.5.5 on 7 Nov 2008.